package com.jdrx.sw.sewage.service;

import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jdrx.platform.commons.rest.beans.vo.ResponseVO;
import com.jdrx.platform.commons.rest.exception.BizException;
import com.jdrx.platform.commons.rest.factory.ResponseFactory2;
import com.jdrx.sw.sewage.beans.dto.AlarmQueryDTO;
import com.jdrx.sw.sewage.beans.dto.CloseAlarmDTO;
import com.jdrx.sw.sewage.beans.dto.StationIdDTO;
import com.jdrx.sw.sewage.beans.entity.AlarmPO;
import com.jdrx.sw.sewage.beans.entity.DictPO;
import com.jdrx.sw.sewage.beans.entity.SequenceDefinePO;
import com.jdrx.sw.sewage.beans.vo.*;
import com.jdrx.sw.sewage.beans.vo.base.PageVO;
import com.jdrx.sw.sewage.common.constant.Constant;
import com.jdrx.sw.sewage.common.enums.EAlarmDict;
import com.jdrx.sw.sewage.common.enums.EAlarmHandleType;
import com.jdrx.sw.sewage.common.enums.EAlarmLevel;
import com.jdrx.sw.sewage.common.enums.EAlarmStatus;
import com.jdrx.sw.sewage.common.util.NumberUtil;
import com.jdrx.sw.sewage.dao.*;
import com.jdrx.sw.sewage.service.base.BaseServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

import static com.jdrx.sw.sewage.common.constant.Constant.*;

@Service
public class AlarmServiceImpl extends BaseServiceImpl {

    public static final Logger logger = LoggerFactory.getLogger(AlarmServiceImpl.class);
    @Value("${spring.application.name}")
    private String platformCode;

    @Autowired
    private AlarmDAO alarmDAO;
    @Autowired
    private AlarmCurveSnapDAO alarmCurveSnapDAO;
    @Autowired
    private AlarmHandleDAO alarmHandleDAO;
    @Autowired
    private AlarmHandleServiceImpl alarmHandleServiceImpl;
    @Autowired
    private SequenceDefineDAO sequenceDefineDao;
    @Autowired
    private AlarmDataHandleServiceImpl alarmDataHandleServiceImpl;
    @Autowired
    private DictServiceImpl dictServiceImpl;
    @Autowired
    ProcessunitDAO processunitDAO;

    public Integer selectAlarmNum(Integer alarmStatus, Integer mAlarmStatus) {
        return alarmDAO.selectAlarmNum(alarmStatus, mAlarmStatus, null);
    }

    public Integer selectAlarmByStationId(Long stationId) throws BizException {
        Map<String, Object> params = new HashMap<>();
        params.put(CLASSIFYKEY, ALARMCLASSIFY);
        params.put(DISNAME, STATION_OUTOFCONTACT_ARREAR);
        DictPO dict = dictServiceImpl.getByParams(params, null);
        return alarmDAO.selectAlarmByStationId(stationId, EAlarmStatus.COMPLETED.getKey(), dict.getId(), "厂站欠费断开");
    }

    public AlarmNumVO selectAllAlarmNum(List<Long> stationIds, String dataNode) throws BizException {
        if (stationIds == null || stationIds.size() <= 0)
            return new AlarmNumVO();

        if (!StringUtils.isEmpty(dataNode)) dataNode = getSQLPerfix(dataNode);

        List<AlarmNumTotalVO> mapList = alarmDAO.countAlarmNum(stationIds, dataNode);
        AlarmNumVO alarmNumVO = new AlarmNumVO();
        if (null == mapList || mapList.size() <= 0) return alarmNumVO;
        mapList.forEach(item -> {
            Integer alarmStatus = item.getAlarmStatus();
            Integer total = item.getTotal();
            if (EAlarmStatus.UNREAD.getKey() == alarmStatus) alarmNumVO.setUnreadAlarmNum(total);
            if (EAlarmStatus.PROCESSING.getKey() == alarmStatus) alarmNumVO.setProcessingAlarmNum(total);
            if (EAlarmStatus.COMPLETED.getKey() == alarmStatus) alarmNumVO.setCompletedAlarmNum(total);
        });
        alarmNumVO.setUnreadAndProcessingAlarmNum(alarmNumVO.getUnreadAlarmNum() + alarmNumVO.getProcessingAlarmNum());
        return alarmNumVO;
    }

    public PageVO<AlarmVO> selectAlarmByPage(AlarmQueryDTO alarmQueryDTO) {
        if (alarmQueryDTO.getStationIds() == null || alarmQueryDTO.getStationIds().size() <= 0)
            return PageVO.toPageVO(Lists.newArrayList());

        PageHelper.startPage(alarmQueryDTO);
        return PageVO.toPageVO(alarmDAO.selectAlarmByPage(alarmQueryDTO));
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateAlarmNumInitValue(String dataNode) throws BizException {
        if (!StringUtils.isEmpty(dataNode)) dataNode = getSQLPerfix(dataNode);
        SequenceDefinePO sequenceDefinePO = sequenceDefineDao.findByKey(Constant.ALARM_NUM_SN_KEY, platformCode, dataNode);
        if (Objects.nonNull(sequenceDefinePO)) {
            sequenceDefineDao.update(sequenceDefinePO.getId(),
                    1L, new Date(), sequenceDefinePO.getRemarks(), dataNode);
        }
    }

    public AlarmDetailsVO selectAlarmDetail(Long alarmId, String dutyUserName) {
        AlarmDetailVO alarmDetailVO = alarmDAO.selectAlarmDetailAndDeviceInfoById(alarmId);
        if (EAlarmDict.DEVICE.getValue().equals(alarmDetailVO.getAlarmTypeName()))//故障次数
            alarmDetailVO.setHistoryFaultNum(alarmDAO.selectAlarmNum(EAlarmStatus.COMPLETED.getKey(), null, alarmDetailVO.getDeviceId()));

        AlarmDetailsVO alarmDetailsVO = new AlarmDetailsVO();
        alarmDetailsVO.setAlarmDetailInfo(alarmDetailVO);
        //曲线快照
        if (EAlarmDict.QUALITY.getValue().equals(alarmDetailVO.getAlarmTypeName())) {
            List<AlarmCurveSnapVO> alarmCurveSnapVOS = alarmCurveSnapDAO.selectListByAlarmId(alarmDetailVO.getId());
            Collections.sort(alarmCurveSnapVOS, (displayVO1, displayVO2) -> displayVO1.getUpdateTime().compareTo(displayVO2.getUpdateTime()));
            alarmDetailsVO.setAlarmCurveSnapList(alarmCurveSnapVOS);
        }

        //处理消息
        alarmDetailsVO.setAlarmHandleList(alarmHandleDAO.selectListByAlarmIdAndHandleType(alarmDetailVO.getId()));

        //如果告警状态为未读则修改为处理中 其他情况不处理
        if (EAlarmStatus.UNREAD.getKey() == alarmDetailVO.getAlarmStatus()) {
            AlarmPO alarmPO = new AlarmPO();
            BeanUtils.copyProperties(alarmDetailVO, alarmPO);
            alarmPO.setAlarmStatus(EAlarmStatus.PROCESSING.getKey());
            alarmDAO.updateAlarmInfoAndLevelAndEndTimeById(alarmPO);
            //状态改为处理中同时增加   管理员张三已阅读
            alarmHandleServiceImpl.handleAlarmSysNews(String.format(Constant.READ_ALARM_HANDLE_DUTY_USER_IDEA, dutyUserName),
                    alarmPO.getId(),
                    EAlarmHandleType.DUTY_USER_HANDLE.getKey(),
                    null,
                    dutyUserName,
                    null);
        }
        return alarmDetailsVO;
    }

    public ResponseVO closeAlarm(CloseAlarmDTO closeAlarmDTO, String dataNode) throws BizException {
        if (null == closeAlarmDTO.getAlarmId()) return ResponseFactory2.err("告警id不能为空");

        AlarmPO alarmPO = alarmDAO.selectAlarmById(closeAlarmDTO.getAlarmId());
        if (null == alarmPO) return ResponseFactory2.err("告警不存在");

        if (EAlarmStatus.COMPLETED.getKey().equals(alarmPO.getAlarmStatus()))
            return ResponseFactory2.err("告警已关闭，不能重复关闭！");

        if (EAlarmDict.OUTOFCONTACT.getValue().equals(alarmPO.getAlarmTypeName())) {
            if (alarmPO.getAlarmInfo().contains("厂站欠费"))
                return alarmDataHandleServiceImpl.userCloseStationArrearsOutfcontact(alarmPO, closeAlarmDTO.getUserName());

            if (alarmPO.getAlarmInfo().contains("网络通信"))
                return alarmDataHandleServiceImpl.devStatusUserTest(alarmPO, closeAlarmDTO.getUserName(), dataNode);
        }

        if (EAlarmDict.DEVICE.getValue().equals(alarmPO.getAlarmTypeName()))
            return alarmDataHandleServiceImpl.userCloseDeviceAlarm(alarmPO, closeAlarmDTO.getUserName());

        if (EAlarmDict.QUALITY.getValue().equals(alarmPO.getAlarmTypeName()))
            return alarmDataHandleServiceImpl.userCloseQualityAlarm(alarmPO, closeAlarmDTO.getUserName());

        return ResponseFactory2.err("告警类型不存在，无法关闭告警");
    }

    public Map<String, Object> findAlarmNumAndAlarmList(StationIdDTO dto) {
        ArrayList<Long> list = new ArrayList<>();
        list.add(dto.getStationId());
        List<AlarmNumTotalVO> mapList = alarmDAO.countAlarmNum(list, null);
        HashMap map = Maps.newHashMap();
        map.put("alarmTotal", 0);
        map.put("completedAlarmNum", 0);
        map.put("noCompletedAlarmNum", 0);
        map.put("alarmList", new ArrayList<>());
        if (null == mapList || mapList.size() <= 0) return map;

        mapList.forEach(item -> {
            Integer alarmStatus = item.getAlarmStatus();
            Integer total = item.getTotal();
            if (EAlarmStatus.UNREAD.getKey().equals(alarmStatus) || EAlarmStatus.PROCESSING.getKey().equals(alarmStatus)) {
                Integer noCompletedAlarmNum = (Integer) map.get("noCompletedAlarmNum");
                map.put("noCompletedAlarmNum", (noCompletedAlarmNum == null ? 0 : noCompletedAlarmNum) + total);
            }
            if (EAlarmStatus.COMPLETED.getKey().equals(alarmStatus)) map.put("completedAlarmNum", total);

            Integer alarmTotal = (Integer) map.get("alarmTotal");
            map.put("alarmTotal", (alarmTotal == null ? 0 : alarmTotal) + total);
        });
        List<AlarmVO> aList = alarmDAO.selectAlarmList(dto.getStationId());
        map.put("alarmList", aList);
        return map;
    }

    public Map<String, Integer> AlarmAnalysis(StationIdDTO dto) {
        List<AlarmAnalysisVO> mapList = alarmDAO.AlarmAnalysis(dto);

        AtomicReference<Integer> redAlarm = new AtomicReference<>(0);
        AtomicReference<Integer> yellowAlarm = new AtomicReference<>(0);
        AtomicReference<Integer> alarmTotal = new AtomicReference<>(0);
        Double redAlarmThan = 0.0;
        Double yellowAlarmThan = 0.0;


        HashMap map = Maps.newHashMap();
        map.put("redAlarm", redAlarm);
        map.put("yellowAlarm", yellowAlarm);
        map.put("alarmTotal", alarmTotal);
        map.put("redAlarmThan", redAlarmThan);
        map.put("yellowAlarmThan", yellowAlarmThan);
        if (null == mapList || mapList.size() <= 0) return map;

        mapList.forEach(item -> {
            Integer alarmLevel = item.getAlarmLevel();
            Integer total = item.getTotal();
            if (EAlarmLevel.ALARM_RED.getKey().equals(alarmLevel)) redAlarm.set(total);
            if (EAlarmLevel.ALARM_YELLOW.getKey().equals(alarmLevel)) yellowAlarm.set(total);

            alarmTotal.set(alarmTotal.get() + total);
        });

        map.put("redAlarm", redAlarm);
        map.put("yellowAlarm", yellowAlarm);
        map.put("alarmTotal", alarmTotal);
        if (alarmTotal.get() > 0) {
            map.put("redAlarmThan", NumberUtil.precision(new BigDecimal(Double.valueOf(redAlarm.get()) / alarmTotal.get()), 2));
            map.put("yellowAlarmThan", NumberUtil.precision(new BigDecimal(Double.valueOf(yellowAlarm.get()) / alarmTotal.get()), 2));
        }
        return map;
    }
}
